package com.mind.adjust.controller;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.read.listener.ReadListener;
import com.mind.adjust.domain.vo.*;
import com.mind.adjust.domain.vo.rulepassdetail.RulePassDetailVo;
import com.mind.adjust.domain.vo.rulepassdetail.RulePassDetailListVo;
import com.mind.cache.lock.DistributedLock;
import com.mind.common.utils.StringUtils;
import com.mind.common.utils.poi.ExcelUtil;
import com.mind.common.utils.poi.ImportExcelResult;
import com.mind.common.utils.poi.ValidationUtils;
import com.mind.customer.domain.vo.RulePassRateListVo;
import com.mind.customer.domain.vo.RulePassRateVo;
import com.mind.system.domain.AjTicketTask;
import com.mind.adjust.service.AjTicketTaskService;
import com.mind.common.web.controller.BaseController;
import com.mind.common.core.domain.AjaxResult;
import com.mind.common.web.page.TableDataInfo;
import com.mind.common.log.annotation.Log;
import com.mind.common.log.enums.BusinessType;
import jakarta.annotation.Resource;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;

import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolation;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 智能审核模块/审核模块/单据任务管理
 *
 * @author makejava
 * @DocView.PathPrefix {{host}}/api/adjust
 * @since 2024-07-17 22:20:04
 */
@RestController
@RequestMapping("adjust/ticketTask")
public class AjTicketTaskController extends BaseController {
    /**
     * 服务对象
     */
    @Autowired
    private AjTicketTaskService ajTicketTaskService;
    @Resource
    private DistributedLock distributedLock;

    /**
     * 获取单据任务列表
     *
     * @param ticketTask 筛选条件
     * @return com.mind.system.domain.AjTicketTask
     */
    @PreAuthorize("@ss.hasPermi('adjust:ticketTask:list')")
    @Log(title = "单据任务列表", businessType = BusinessType.QUERY)
    @GetMapping("/list")
    public TableDataInfo list(AjTicketTask ticketTask)
    {
        startPage();
        List<AjTicketTask> list = ajTicketTaskService.selectTicketTaskList(ticketTask);
        return getDataTable(list);
    }
    
    /**
     * 单据任务导入
     *
     * @return 结果
     */
//    @RequiresPermissions("adjust:ticketTask:import")
    @Log(title = "单据任务导入", businessType = BusinessType.IMPORT)
    @PostMapping("/import")
    public AjaxResult importExcel(MultipartFile file) throws IOException {
        List<AjTicketTask> cachedDataList = new ArrayList<>();
        List<ImportExcelResult> errorList = new ArrayList<>();
        EasyExcel.read(file.getInputStream(), AjTicketTask.class, new ReadListener<AjTicketTask>() {

            @Override
            public void invoke(AjTicketTask data, AnalysisContext context) {
                Set<ConstraintViolation<AjTicketTask>> violations = ValidationUtils.getValidator().validate(data);
                if(violations.size() > 0){
                    throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), 0, null, null, "");
                }
                cachedDataList.add(data);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                saveData();
            }

            /**
             * 加上存储数据库
             */
            private void saveData() {
                int i = ajTicketTaskService.batchInsert(cachedDataList);
            }

            /**
             * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
             *
             * @param exception
             * @param context
             * @throws Exception
             */
            @Override
            public void onException(Exception exception, AnalysisContext context) {
                // 如果是某一个单元格的转换异常 能获取到具体行号
                // 如果要获取头的信息 配合invokeHeadMap使用
                if (exception instanceof ExcelDataConvertException) {
                    ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
                    String errMsg = String.format("第%d行数据验证异常", excelDataConvertException.getRowIndex());
                    errorList.add(new ImportExcelResult(){{
                        setRow(excelDataConvertException.getRowIndex());
                        setCol(excelDataConvertException.getColumnIndex());
                        setError(errMsg);
                    }});
                }
            }
        }).sheet().doRead();
        if(errorList.size() > 0) {
            return AjaxResult.success(String.format("一共%d条，成功导入%d条，错误%d条。错误详情：%s", cachedDataList.size() + errorList.size(), cachedDataList.size(), errorList.size(), errorList.stream().map(ImportExcelResult::getError).collect(Collectors.joining("\r\n"))));
        }else{
            return AjaxResult.success(String.format("一共%d条，成功导入%d条，错误0条。", (cachedDataList.size()), cachedDataList.size()));
        }
    }

    /**
     * 附件类型下载模板
     * @return 结果
     */
    @Log(title = "单据任务下载模板", businessType = BusinessType.DOWNLOAD)
//    @RequiresPermissions("adjust:attachType:download")
    @GetMapping("/downloadTemplate")
    public void downloadTemplate(HttpServletResponse response) throws IOException {
        ExcelUtil<AjTicketTask> util = new ExcelUtil<>(AjTicketTask.class);
        String fileName =  URLEncoder.encode("单据任务模板", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        util.exportExcel(response, new ArrayList<>(), "单据任务数据");
    }
    
    /**
     * 单据任务导出
     *
     * @param ticketTask 筛选条件
     * @return 结果
     */
    @Log(title = "单据任务导出", businessType = BusinessType.EXPORT)
//    @RequiresPermissions("adjust:ticketTask:export")
    @PostMapping(value = "/export", produces = "application/octet-stream")
    public void export(HttpServletResponse response, AjTicketTask ticketTask) throws IOException {
        // 获取数据列表
        List<AjTicketTask> list = ajTicketTaskService.selectTicketTaskList(ticketTask);

        // 创建Excel工具类实例
        ExcelUtil<AjTicketTask> util = new ExcelUtil<>(AjTicketTask.class);

        // 设置下载的文件名，并进行URL编码
        String filename = "智能查验列表.xlsx";
        String encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFilename);

        // 导出Excel文件
        util.exportExcel(response, list, "智能查验数据");
    }

    /**
     * 根据ID获取单据任务详情
     * @return com.mind.system.domain.AjTicketTask
     */
//    @RequiresPermissions("adjust:ticketTask:query")
    @GetMapping(value = "/{ticketTaskId}")
    public AjaxResult getInfo(@PathVariable Long ticketTaskId)
    {
        return success(ajTicketTaskService.selectTicketTaskById(ticketTaskId));
    }

    /**
     * 新增单据任务
     * @return 结果
     */
    @PreAuthorize("@ss.hasPermi('adjust:ticketTask:add')")
    @Log(title = "单据任务新增", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody AjTicketTask ticketTask)
    {
        return toAjax(ajTicketTaskService.insertTicketTask(ticketTask));
    }

    /**
     * 修改单据任务
     * @return 结果
     */
    @PreAuthorize("@ss.hasPermi('adjust:ticketTask:edit')")
    @Log(title = "单据任务修改", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody AjTicketTask ticketTask)
    {
        // 20250320释放锁
        AjTicketTask checkTask = ajTicketTaskService.selectTicketTaskById(Long.parseLong(ticketTask.getId().toString()));
        if(checkTask!=null) {
            this.distributedLock.tryUnlock(checkTask.getTicketId());
        }
        return toAjax(ajTicketTaskService.updateTicketTask(ticketTask));
    }

    /**
     * 删除单据任务
     * @return 结果
     */
    @PreAuthorize("@ss.hasPermi('adjust:ticketTask:remove')")
    @Log(title = "单据任务删除", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ticketTaskIds}")
    public AjaxResult remove(@PathVariable Long[] ticketTaskIds)
    {
        return toAjax(ajTicketTaskService.deleteTicketTaskByIds(ticketTaskIds));
    }

    /**
     * 触发查验
     * @return 结果
     */
    @Log(title = "触发查验", businessType = BusinessType.DELETE)
    @PostMapping("/check")
    public AjaxResult check(@RequestBody AjTicketTask task)
    {
        // 20250320释放锁
        AjTicketTask checkTask = ajTicketTaskService.selectTicketTaskById(Long.parseLong(task.getId().toString()));
        if(checkTask!=null) {
            this.distributedLock.tryUnlock(checkTask.getTicketId());
        }
        return toAjax(ajTicketTaskService.check(task));
    }

    /**
     * 智审明细报表查询
     * @return 结果
     */
    @GetMapping("/smartCheckDetail")
    public AjaxResult smartCheckDetail(AjTicketTask task)
    {
        return AjaxResult.success(ajTicketTaskService.smartCheckDetail(task));
    }

    /**
     * 智审明细报表导出
     * @return 结果
     */
    @PostMapping("/smartCheckDetail/export")
    public void smartCheckDetailExport(HttpServletResponse response,AjTicketTask task) throws UnsupportedEncodingException {
        // 获取数据列表
        List<TicketDetailListVo> list = ajTicketTaskService.smartCheckDetail(task);

        // 创建Excel工具类实例
        ExcelUtil<TicketDetailListVo> util = new ExcelUtil<>(TicketDetailListVo.class);

        // 设置下载的文件名，并进行URL编码
        String filename = "智审明细报表.xlsx";
        String encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFilename);

        // 导出Excel文件
        util.exportExcel(response, list, "智审明细报表");
    }


    /**
     * 智审通过单量
     * @return 结果
     */
    @GetMapping("/smartCheckPassList")
    public AjaxResult smartCheckPassList(AjTicketTask task)
    {
        RulePassDetailVo result = new RulePassDetailVo();
        List<RulePassDetailListVo> smartCheckDetailListVos = ajTicketTaskService.smartCheckPassList(task);

        result.setDetailListVos(smartCheckDetailListVos);
        result.setPassTicketCount(smartCheckDetailListVos.stream().filter(smartCheckDetailListVo -> smartCheckDetailListVo.getFailCount() == 0).count());
        return AjaxResult.success(result);
    }

    /**
     * 智审通过单量导出
     * @return 结果
     */
    @PostMapping("/smartCheckPassList/export")
    public void smartCheckPassListExport(HttpServletResponse response,AjTicketTask task) throws UnsupportedEncodingException {
        // 获取数据列表
        List<RulePassDetailListVo> list = ajTicketTaskService.smartCheckPassList(task);

        // 创建Excel工具类实例
        ExcelUtil<RulePassDetailListVo> util = new ExcelUtil<>(RulePassDetailListVo.class);

        // 设置下载的文件名，并进行URL编码
        String filename = "智审通过单量报表.xlsx";
        String encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFilename);

        // 导出Excel文件
        util.exportExcel(response, list, "智审通过单量报表");
    }

    /**
     * 智审通过率查询
     * @return 结果
     */
    @GetMapping("/smartCheckPassRate")
    public AjaxResult smartCheckPassRate(AjTicketTask task)
    {
        RulePassRateVo result = new RulePassRateVo();
        List<RulePassRateListVo> rulePassRateListVos = ajTicketTaskService.smartCheckPassRate(task);
        result.setRulePassRateListVos(rulePassRateListVos);
        AtomicInteger count = new AtomicInteger();
        AtomicInteger passCount = new AtomicInteger();
        rulePassRateListVos.forEach(rulePassRateListVo -> {
            count.addAndGet(rulePassRateListVo.getCount());
            passCount.addAndGet(rulePassRateListVo.getPassCount());
        });
        if(count.get() > 0) {
            result.setPassRate(Math.round(passCount.get() * 1.0 / count.get() * 10000) / 10000.0);
        }else{
            result.setPassRate(0.0);
        }
        return AjaxResult.success(result);
    }

    /**
     * 智审通过率导出
     * @return 结果
     */
    @PostMapping("/smartCheckPassRate/export")
    public void smartCheckPassRateExport(HttpServletResponse response,AjTicketTask task) throws UnsupportedEncodingException {
        // 获取数据列表
        List<RulePassRateListVo> list = ajTicketTaskService.smartCheckPassRate(task);

        // 创建Excel工具类实例
        ExcelUtil<RulePassRateListVo> util = new ExcelUtil<>(RulePassRateListVo.class);

        // 设置下载的文件名，并进行URL编码
        String filename = "智审通过率报表.xlsx";
        String encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFilename);

        // 导出Excel文件
        util.exportExcel(response, list, "智审通过率报表");
    }

    /**
     * 智审规则覆盖率查询
     * @return 结果
     */
    @GetMapping("/smartCheckRuleOverRate")
    public AjaxResult smartCheckRuleOverRate(AjTicketTask task)
    {
        return AjaxResult.success(ajTicketTaskService.smartCheckRuleOverRate(task));
    }

    /**
     * 智审规则覆盖率导出
     * @return 结果
     */
    @PostMapping("/smartCheckRuleOverRate/export")
    public void smartCheckRuleOverRateExport(HttpServletResponse response,AjTicketTask task) throws UnsupportedEncodingException {
        // 获取数据列表
        List<RuleOverDetailVo> list = ajTicketTaskService.smartCheckRuleOverRate(task);

        // 创建Excel工具类实例
        ExcelUtil<RuleOverDetailVo> util = new ExcelUtil<>(RuleOverDetailVo.class);

        // 设置下载的文件名，并进行URL编码
        String filename = "智审规则覆盖率报表.xlsx";
        String encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFilename);

        // 导出Excel文件
        util.exportExcel(response, list, "智审规则覆盖率报表");
    }

}


